// factory - creating elements
//
// 'iterator' : { [ 'from':0, 'thru':9'[, 'inc':1] | 'set':<object or array> ], 'function' : function(i,v) { ...; return element or something } }

Element.prototype.appendE = function() {
	// create fragment using arguments, append that onto element
	this.appendChild( E.f( {'callee':this}, (Array.prototype.slice.call(arguments)) ) );
	return this;
}

Element.prototype.replaceE = function() {
	// remove children; create fragment using arguments, append that onto element
	while( this.lastChild ) this.removeChild( this.lastChild );
	this.appendChild( E.f( {'callee':this}, (Array.prototype.slice.call(arguments)) ) );
	return this;
}

// make easy to create element via html
var E = {

// environment, eg, env.button = {'.cs__', 's.width:48%'};
'env': {},

'E': function( tag ) {
	// element itself
	//-console.log( 'E.'+tag+', pre='+this.pre );
	var element = (tag=='fragment') ? document.createDocumentFragment() : document.createElement(tag);
	var callee = element;
	// default env
	if( E.env[tag] ) addElement( E.env[tag] );
	// arguments
	for( var i=1; i<arguments.length; i++ ) addElement(arguments[i]);
	//-console.log( '- - - - return E.'+tag+': '+element );
	return element;

	function addElement( arg ) {

		//-console.log( tag+' addElement: '+arg );

		// if null, ignore
		if( arg === null ) return;

		// if fragment, append
		else if( arg instanceof DocumentFragment ) {
			element.appendChild( arg );
		}

		// array - recur
		else if( arg instanceof Array ) {
			//-console.log( tag+' adding array: '+arg );
			for( var j=0; j<arg.length; j++ )  addElement(arg[j]);
		}

		// if ol or ul, make object into li
		else if( ( tag == 'ol' || tag == 'ul' ) && typeof arg == 'object' ) {
			//-console.log( "ul object: "+arg );
			if( arg instanceof HTMLLIElement )	element.appendChild( arg );
			else					element.appendChild( E.li( arg ) );
		}

		// non-object - deal with it a text
		else if( typeof arg != 'object' ) {

			//-console.log( 'tag='+tag+', text: ' + arg );

			// boolean and numeric types
			if( typeof arg == 'boolean' ) {
				if( tag=='input' &&( element.type=='radio' || element.type=='checkbox' ) ) element.checked = arg;
				else if( tag=='input' || tag=='textarea' )	element.value = (arg) ? 1 : 0;
				else						element.appendChild( document.createTextNode((arg)?'true':'false') );
			}
			else if( typeof arg == 'number' ) {
				if( tag=='input' || tag=='textarea' )	element.value = arg
				else					element.appendChild( document.createTextNode(arg) );
			}

			// truth tags
			else if( arg=='readonly' || arg=='checked' || arg=='enabled' || arg=='disabled' || arg=='required' || arg=='unique' ) {
									element[arg] = true;
			}
			else if( arg=='nochecked' ) 			element[checked] = false;
			else if( arg=='nodml' )				element[dml] = false;
			else if( arg=='verify' ) {
									element.verify = true;
									element.addEventListener('change',util.colVerifyDB);
			}
			else if( arg.substr(0,1)=='`' ) {
				if( tag=='input' || tag=='textarea' )	element.value = arg.substr(1);
				else					element.appendChild( document.createTextNode(arg.substr(1)) );
			}

			// id, name, class, value
			else if( arg.substr(0,1)=='#' )			callee.id = arg.substr(1);
			else if( arg.substr(0,1)==':' )			callee.setAttribute( 'name', (this.genName)? this.genName(arg.substr(1)) : arg.substr(1) );
			else if( arg.substr(0,1)=='.' )			callee.className = (callee.className) ? callee.className+' '+arg.substr(1) : arg.substr(1);
			else if( arg.substr(0,1)=='=' )			callee.value = arg.substr(1);

			// attribute, event listener, style
			else if( match_arr = arg.match(/a\.(.+):(.*)/))	callee.setAttribute(match_arr[1],match_arr[2]);
			else if( match_arr = arg.match(/e\.(.+):(.*)/))	callee.AddEventListener(match_arr[1],match_arr[2]);
			else if( match_arr = arg.match(/s\.(.+):(.*)/))	callee.style[match_arr[1]] = match_arr[2];

			// checkbox value / checked
			else if( element.type == 'checkbox' )	switch( arg ) {
								case '1':	element.value = '1';
										element.checked = true;
										break;
								case '0':	element.value = '1';
										element.checked = false;
										break;
								case 't':	element.value = 't';
										element.checked = true;
										break;
								case 'f':	element.value = 't';
										element.checked = false;
										break;
								}

			// input, textarea value
			else if( tag=='input' || tag=='textarea' )	element.value = arg;

			// select: add as option
			else if( tag == 'select' && (match_arr = arg.match( "^(.*):(.*)$") ) ) 
							element.appendChild( E.option( match_arr[1], match_arr[2], match_arr[1]==element.getAttribute('orig_val') ) );
			else if( tag == 'select' ) 	element.appendChild( E.option( arg, arg, arg==element.getAttribute('orig_val') ) );

			// list: add as list item
			else if( tag == 'ol' || tag == 'ul' )	element.appendChild( E.li( arg ) );
			else					element.appendChild( document.createTextNode(arg) );
		}
		
		// html element - append
		else if( arg instanceof Element ) {
			//-console.log( 'element: ' + arg );
			element.appendChild( arg );
		}
		
		// non-html object
		else {
			//-console.log( 'attributes in object  - - - -' );
			for( var attr in arg ) if( typeof attr == 'string' ) {

				var match_arr;
				// iterator
				if( attr == 'iterator' ) {
					// from - thru iterator - whether or not operating on an object/array
					if( arg[attr].from!=undefined && arg[attr].thru!=undefined && arg[attr].set==undefined ) {
						var inc = (arg[attr].inc != undefined ) ? arg[attr].inc : ((arg[attr].from<=arg[attr].thru)?1:-1);
						for( var i = arg[attr].from; i<=arg[attr].thru; i+=inc ) {
							if( arg[attr].set == undefined ) addElement( (arg[attr]['function'])(i) );
							else				 addElement( (arg[attr]['function'])(i,arg[attr][i]) );
						}
					}
					// operating on an object/array with length property
					else if( arg[attr].set.length != undefined ) {
						for( var i = 0; i<arg[attr].set.length; i++ ) {
							addElement( (arg[attr]['function'])(i,arg[attr].set[i]) );
						}
					}
					// elements in an object without a length property
					else if( arg[attr].set ) {
						for( var i in arg[attr].set ) if( typeof i != 'function' ) {
							addElement( (arg[attr]['function'])(i,arg[attr].set[i]) );
						}
					}
				}
				// text
				if( attr == 'text' ) {
					element.appendChild( document.createTextNode(arg[attr]) );
				}
				// style
				else if( match_arr = attr.match(/^(style|s)\.(.*)/ ) ) {
					callee.style[match_arr[2]] = arg[attr];
				}
				// event
				else if( match_arr = attr.match(/^(event|e)\.(.*)/) ) {
					if( arg[attr] ) callee.addEventListener(match_arr[2],arg[attr],true);
				}
				// attributes
				else if( match_arr = attr.match(/^(attribute|a)\.(.*)/) ) {
					callee.setAttribute( match_arr[2], arg[attr] );

				}
				// callee
				else if( attr == 'callee' ) {
					callee = arg[attr];
					//-console.log( 'callee set to '+arg[attr] );
				}
				// value
				else if( attr == 'value' ) {
					//-console.log( 'value: '+callee.tagName+' set to '+arg[attr] );
					if( callee.tagName == 'SELECT' )	callee.setAttribute('orig_val',arg[attr]);
					else					callee.value = arg[attr];
				}
				// select option
				else if( tag == 'select' ) {
					//-console.log( 'append option: value='+callee.value );
					callee.appendChild( E.option( attr, arg[attr], (callee.getAttribute('orig_val') == attr) ) );
				}
				// properties
				else	callee[attr] = arg[attr];
			}
		}
	}
},

// set( {defaults}, E.tag( locals ), ... ) === E.tag( locals, {defaults} ), ...
// note!! default values overwrite local values!!
'defaults': function(  ) {
	var args = Array.prototype.slice.call(arguments);
	var dflt = args.shift();
	var f = E.f();
	//-Array.forEach( arguments, function(e) { 
	args.forEach( function(e) { 
			//-console.log( 'scoper: e='+e+', HTMLElement='+(e instanceof HTMLElement )+', dflt='+dflt );
			if( e instanceof HTMLElement ) e.appendE( dflt );
			else if( e instanceof DocumentFragment ) null;
			else e = document.createTextNode(e);
			//-console.log( 'result='+e );
			f.appendChild( e );
		} );
	//-console.log( 'return: '+f+' - '+f.childNodes.length );
	//-for( var i=0; i<f.childNodes.length; i++ ) console.log( 'child: '+f.childNodes[i] );
	return f;
},
// TR: [class] attrs elements or innerHTML
'div': function() { return E.E('div',Array.prototype.slice.call(arguments)) },
'span': function() { return E.E('span',Array.prototype.slice.call(arguments)) },
'f': function() { return E.E('fragment',Array.prototype.slice.call(arguments)) },
'table': function() { return E.E('table',Array.prototype.slice.call(arguments)) },
'thead': function() { return E.E('thead',Array.prototype.slice.call(arguments)) },
'tbody': function() { return E.E('tbody',Array.prototype.slice.call(arguments)) },
'tfoot': function() { return E.E('tfoot',Array.prototype.slice.call(arguments)) },
'tr': function() { return E.E('tr',Array.prototype.slice.call(arguments)) },
'td': function() { return E.E('td',Array.prototype.slice.call(arguments)) },
'th': function() { return E.E('th',Array.prototype.slice.call(arguments)) },
'button': function( click ) { return E.E( 'button', {'event.click':click}, Array.prototype.slice.call(arguments,1) ); },
'a': function( href, click ) { 
	return E.E( 'a', {'href':href,'event.click':click}, Array.prototype.slice.call(arguments,2) );
},

'form': function() { return E.E('form',Array.prototype.slice.call(arguments)) },
'input': function() { return E.E('input',{'type':'text'},Array.prototype.slice.call(arguments)) },
'password': function() { return E.E('input',{'type':'password'},Array.prototype.slice.call(arguments)) },
'hidden': function() { return E.E('input',{'type':'hidden'},Array.prototype.slice.call(arguments)) },
'checkbox': function() { return E.E('input',{'type':'checkbox'},Array.prototype.slice.call(arguments)) },
'textarea': function() { return E.E('textarea',Array.prototype.slice.call(arguments)) },
'radio': function() { return E.E('input',{'type':'radio'},Array.prototype.slice.call(arguments)) },
'i': function() { return E.E('i',Array.prototype.slice.call(arguments)) },
'b': function() { return E.E('b',Array.prototype.slice.call(arguments)) },
's': function() { return E.E('s',Array.prototype.slice.call(arguments)) },
'code': function() { return E.E('code',Array.prototype.slice.call(arguments)) },
'select': function() { return E.E('select',Array.prototype.slice.call(arguments)) },
'option': function( value, label, selected ) {
	//-console.log( 'op_tion: '+value+', '+label+', '+selected );
	var o = document.createElement('option');
	o.value = value;
	o.appendChild( document.createTextNode(label) );
	if( selected ) o.selected = true;
	return o;
},

'ul': function() { return E.E('ul',Array.prototype.slice.call(arguments)) },
'ol': function() { return E.E('ol',Array.prototype.slice.call(arguments)) },
'li': function() { return E.E('li',Array.prototype.slice.call(arguments)) },

'h1': function() { return E.E('h1',Array.prototype.slice.call(arguments)) },
'h2': function() { return E.E('h2',Array.prototype.slice.call(arguments)) },
'h3': function() { return E.E('h3',Array.prototype.slice.call(arguments)) },
'h4': function() { return E.E('h4',Array.prototype.slice.call(arguments)) },

'br': function() { return E.E('br',Array.prototype.slice.call(arguments)) },
'hr': function() { return E.E('hr',Array.prototype.slice.call(arguments)) },

'text': function() { return document.createTextNode( Array.prototype.slice.call(arguments).join(' ') ) }

}
